#pragma once
#include "Comm.h"
#include "Atom.h"
#include "ThreadLock.h"

namespace COMM
{
	class COMM_API CommonDestructor
	{
	public:
		CommonDestructor(void* ptr):m_ptr(ptr){}
		virtual ~CommonDestructor(){}
		void* ptr(){ return m_ptr;}
		virtual void Release(){ delete this;}
		virtual void Delete() = 0;
	protected:
		void* m_ptr;
	};

	class COMM_API SharedPtrImp
	{
	public:
		static int PtrInstanceCount();
		SharedPtrImp(CommonDestructor* destructor);
		virtual ~SharedPtrImp();
		SharedPtrImp(const SharedPtrImp& rhs);
		SharedPtrImp& operator=(const SharedPtrImp& rhs);
		void Release();

	protected:
		void* ptr() const;
	private:
		CommonDestructor* m_destructor;
	};

	class COMM_API ScopedPtrImp
	{
		MYLIB_NONCOPIED_CLASS(ScopedPtrImp);
	public:
		explicit ScopedPtrImp(CommonDestructor* destructor);
		~ScopedPtrImp();
		void Release();
		
	protected:
		void* ptr() const;
		void* detach();
		void attach(CommonDestructor* destructor);
	private:
		CommonDestructor* m_destructor;
	};

	
	template <class T>
	class CommonPtrDestructor : public CommonDestructor
	{
	public:
		CommonPtrDestructor(T* ptr):CommonDestructor(ptr){}
		virtual void Delete(){ if(NULL!=m_ptr){ delete (T*)m_ptr; m_ptr=NULL;}}
	};


	// MT-Safe
	//
	template<class T, class D=CommonPtrDestructor<T> >
	class SharedPtr : public SharedPtrImp
	{
	public:
		SharedPtr(T* ptr=NULL)
			:SharedPtrImp(new D(ptr)){}
		T* get(){ return (T*)ptr();}
		const T* get() const{ return (T*)ptr();}
		T* operator->(){ return get();}
		const T* operator->() const{ return get();}
		operator T*(){ return get();}
		operator const T*() const{ return get();}
		bool operator==(const T* ptr) const { return (ptr == get());}
		bool operator!=(const T* ptr) const { return (ptr != get());}
	};


	// NOT MT-Safe
	//
	template<class T, class D=CommonPtrDestructor<T> >
	class ScopedPtr : public ScopedPtrImp
	{
	public:
		explicit ScopedPtr(T* ptr=NULL)
			:ScopedPtrImp(new D(ptr)){}
		// Must be released by yourself.
		T* Detach(){ return (T*)detach();}
		ScopedPtr& Attach(T* ptr){ attach(new D(ptr)); return *this;}
		ScopedPtr& operator=(T* ptr){ return Attach(ptr);}
		T* get(){ return (T*)ptr();}
		const T* get() const{ return (T*)ptr();}
		T* operator->(){ return get();}
		const T* operator->() const{ return get();}
		operator T*(){ return get();}
		operator const T*() const{ return get();}
		bool operator==(const T* ptr) const { return (ptr == get());}
		bool operator!=(const T* ptr) const { return (ptr != get());}
	};
	
}
	


